package com.clkj.xiuzheng.service.shangcheng;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.clkj.xiuzheng.dao.shangcheng.*;
import com.clkj.xiuzheng.pojo.common.*;
import com.clkj.xiuzheng.pojo.shangcheng.*;
import com.clkj.xiuzheng.pojo.shangcheng.vo.WebOrder;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.exception.MalformedMessageException;
import com.wechat.pay.java.core.notification.NotificationConfig;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.core.notification.RequestParam;
import com.wechat.pay.java.core.util.PemUtil;
import com.wechat.pay.java.service.partnerpayments.app.model.Transaction;
import okhttp3.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import tk.mybatis.mapper.entity.Example;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.bind.ValidationException;
import java.io.*;
import java.security.PrivateKey;
import java.util.*;

/**
 * @author yawang
 * @create 2024/05/17 10:53:06
 **/
@Service
public class PayServiceImpl implements PayService{
    @Autowired
    private ScOrderMapper orderMapper;
    @Autowired
    private ScUserMapper userMapper;

    @Autowired
    private ScVipLevelNumMapper levelNumMapper;
    @Autowired
    private UserScoreMapper userScoreMapper;
    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private UserCommissionMapper commissionsMapper;

    @Autowired
    private UserCommDetailMapper detailsMapper;


    private Map map;

    @Autowired
    private PondMapper pondMapper;
    @Autowired
    private WebOrderMapper webOrderMapper;

    private  WechatPayConfig wechatPayConfig;
    private  RSAAutoCertificateConfig rsaConfig;


    @Override
    public Map wxPay(String openId, String totalMoney, String orderNum, Integer userId, HttpServletRequest request) {

//        testPaySuccess(orderNum,userId);
//        return null;

        String attach = userId + "@"+orderNum;
        orderNum = orderNum+"A"+((int) (Math.random() * 90) + 10);;
        String redirect_url="https://www.ccclkj.cn:2036/pay/paySuccess";


        String nonceStr = DateFormatHelper.getCurTimestamp().toString();
        String Ip = Util.getIpAddr(request);
        String totalFee = Util.getMoney(totalMoney.toString());
        String body = "商城购物";


        SortedMap<String,Object> packageParams = new TreeMap();
        packageParams.put("appid", WxApi.getMiniAppId());
        packageParams.put("attach",attach);
        packageParams.put("body",body);
        packageParams.put("mch_id", WxApi.getMchId());
        packageParams.put("nonce_str", nonceStr);
        packageParams.put("notify_url",redirect_url);
        packageParams.put("out_trade_no",orderNum);
        packageParams.put("spbill_create_ip", Ip);
        packageParams.put("total_fee",totalFee);
        packageParams.put("trade_type","APP");
        RequestHandler requestHandler = new RequestHandler(null,null);
        requestHandler.init(WxApi.getMiniAppId(),WxApi.getMiniAppSecret() ,WxApi.getPartnerkey(),WxApi.getMchId());
        String sign = requestHandler.createSign(packageParams);
        System.out.println(sign);
        String xml = "<xml>" + "<appid>" + WxApi.getMiniAppId() + "</appid>" + "<attach>"
                + attach + "</attach>" + "<body><![CDATA[" + body
                + "]]></body>" + "<mch_id>" + WxApi.getMchId() + "</mch_id>"
                + "<nonce_str>" + nonceStr + "</nonce_str>" + "<notify_url>"
                + redirect_url + "</notify_url>" + "<out_trade_no>"
                + orderNum + "</out_trade_no>" +
                "<spbill_create_ip>" + Ip + "</spbill_create_ip>"
                + "<sign>" + sign + "</sign>" + "<total_fee>" + totalFee
                + "</total_fee>" + "<trade_type>" + "APP"
                + "</trade_type>" +
                "</xml>";
        System.out.println(xml);
        String prePayId = "";
        String createdOrderURL = "https://api.mch.weixin.qq.com/pay/unifiedorder";
        String result = PayUtil.httpRequest(createdOrderURL,"POST",xml);
        System.out.println(result);
        SortedMap<String,Object> finalpackage = new TreeMap();
        try {
            Map map = PayUtil.doXMLParse(result);
            String str = String.valueOf(System.currentTimeMillis()/1000);
            String returnCode = map.get("return_code").toString();
            if(returnCode.equals("SUCCESS")){
                prePayId = map.get("prepay_id").toString();
                finalpackage.put("appid",WxApi.getMiniAppId());
                finalpackage.put("noncestr",nonceStr);
                finalpackage.put("package","Sign=WXPay");
                finalpackage.put("partnerid",WxApi.getMchId());
                finalpackage.put("prepayid",prePayId);
                finalpackage.put("timestamp",str);
                String finalSign = requestHandler.createSign(finalpackage);
                finalpackage.put("sign",finalSign);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        map = new HashMap();
        map.put("finalPackage",finalpackage);

        return map;
    }

    @Override
    public void paySuccess(HttpServletRequest request, HttpServletResponse response) {
        System.out.println( "支付回调");
        String resXml = "";
        InputStream inStream;
        Integer userId = null;
        String orderNum = "";
        try {
            inStream = request.getInputStream();
            ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int len = 0;
            while ((len = inStream.read(buffer)) != -1) {
                outSteam.write(buffer, 0, len);
            }
            outSteam.close();
            inStream.close();
            String result = new String(outSteam.toByteArray(), "utf-8");// 获取微信调用我们notify_url的返回信息
            Map m = PayUtil.parseXmlToList2(result);
            BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
            if ("SUCCESS".equals(m.get("result_code").toString())) {
                String attach = m.get("attach").toString();
                String []str  = attach.split("@");
                Example example =new Example(Order.class);
                Example.Criteria criteria =  example.createCriteria();
                criteria.andEqualTo("numberFlag",str[1]);
                Order order = new Order();
                order.setOrderStatus(1);
                orderMapper.updateByExampleSelective(order,example);
                userId = Integer.parseInt(str[0]);
                orderNum=str[1];
                resXml = "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml> ";

            } else {
                resXml = "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[报文为空]]></return_msg></xml>";

            }
            out.write(resXml.getBytes());
            out.flush();
            out.close();
            //更新用户账户
            updateUser(userId,orderNum);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public Map userRecharge(Integer userId, String rechargeMoney, Integer scoreNum, Integer diamondNum,String commissionNum,HttpServletRequest request) {
        String orderNum = String.valueOf(new Date().getTime() / 1000);
        String redirect_url="https://www.ccclkj.cn:2036/pay/paySuccessRecharge";

        String attach = userId + "@"+scoreNum+"@"+diamondNum+"@"+commissionNum+"@"+rechargeMoney;


        String nonceStr = DateFormatHelper.getCurTimestamp().toString();
        String Ip = Util.getIpAddr(request);
        String totalFee = Util.getMoney(rechargeMoney);
        String body = "会员充值";


        SortedMap<String,Object> packageParams = new TreeMap();
        packageParams.put("appid", WxApi.getMiniAppId());
        packageParams.put("attach",attach);
        packageParams.put("body",body);
        packageParams.put("mch_id", WxApi.getMchId());
        packageParams.put("nonce_str", nonceStr);
        packageParams.put("notify_url",redirect_url);
        packageParams.put("out_trade_no",orderNum);
        packageParams.put("spbill_create_ip", Ip);
        packageParams.put("total_fee",totalFee);
        packageParams.put("trade_type","APP");
        RequestHandler requestHandler = new RequestHandler(null,null);
        requestHandler.init(WxApi.getMiniAppId(),WxApi.getMiniAppSecret() ,WxApi.getPartnerkey(),WxApi.getMchId());
        String sign = requestHandler.createSign(packageParams);
        System.out.println(sign);
        String xml = "<xml>" + "<appid>" + WxApi.getMiniAppId() + "</appid>" + "<attach>"
                + attach + "</attach>" + "<body><![CDATA[" + body
                + "]]></body>" + "<mch_id>" + WxApi.getMchId() + "</mch_id>"
                + "<nonce_str>" + nonceStr + "</nonce_str>" + "<notify_url>"
                + redirect_url + "</notify_url>" + "<out_trade_no>"
                + orderNum + "</out_trade_no>" +
                "<spbill_create_ip>" + Ip + "</spbill_create_ip>"
                + "<sign>" + sign + "</sign>" + "<total_fee>" + totalFee
                + "</total_fee>" + "<trade_type>" + "APP"
                + "</trade_type>" +
                "</xml>";
        System.out.println(xml);
        String prePayId = "";
        String createdOrderURL = "https://api.mch.weixin.qq.com/pay/unifiedorder";
        String result = PayUtil.httpRequest(createdOrderURL,"POST",xml);
        System.out.println(result);
        SortedMap<String,Object> finalpackage = new TreeMap();
        try {
            Map map = PayUtil.doXMLParse(result);
            String str = String.valueOf(System.currentTimeMillis()/1000);
            String returnCode = map.get("return_code").toString();
            if(returnCode.equals("SUCCESS")){
                prePayId = map.get("prepay_id").toString();
                finalpackage.put("appid",WxApi.getMiniAppId());
                finalpackage.put("noncestr",nonceStr);
                finalpackage.put("package","Sign=WXPay");
                finalpackage.put("partnerid",WxApi.getMchId());
                finalpackage.put("prepayid",prePayId);
                finalpackage.put("timestamp",str);
                String finalSign = requestHandler.createSign(finalpackage);
                finalpackage.put("sign",finalSign);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        map = new HashMap();
        map.put("finalPackage",finalpackage);

        return map;

    }

    @Override
    public void paySuccessRecharge(HttpServletRequest request, HttpServletResponse response) {
        System.out.println( "会员充值支付回调");
        String resXml = "";
        String str = "";
        InputStream inStream;
        try {
            inStream = request.getInputStream();
            ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int len = 0;
            while ((len = inStream.read(buffer)) != -1) {
                outSteam.write(buffer, 0, len);
            }
            outSteam.close();
            inStream.close();
            String result = new String(outSteam.toByteArray(), "utf-8");// 获取微信调用我们notify_url的返回信息
            Map m = PayUtil.parseXmlToList2(result);
            BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
            if ("SUCCESS".equals(m.get("result_code").toString())) {
                str = m.get("attach").toString();


                resXml = "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml> ";

            } else {
                resXml = "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[报文为空]]></return_msg></xml>";

            }
            out.write(resXml.getBytes());
            out.flush();
            out.close();
            //更新用户账户
            updateUserRecharge(str);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static String HOST = "https://api.mch.weixin.qq.com";
    private static String METHOD = "POST";
    private static String PATH = "/v3/pay/transactions/native";

    @Override
    public String  webPay(String goodsName, Integer price, Integer userId) {
        Map requestMap = new HashMap();
        String appid = "wx3be50f8d4f94f23f";
        String mchid = "1729397933";
        String description = "产品知识付费";
        String outTradeNo = Util.getRandomStringByLength(20);
        String attach = userId+"@"+goodsName;
//        String url ="https://www.ccclkj.cn:2028/orders/payPurchaseOrder";
        String notifyUrl = "https://www.ccclkj.cn:2036/pay/webPaySuccess";
        Map amountMap = new HashMap();
        amountMap.put("total",price);
        amountMap.put("currency","CNY");

        requestMap.put("appid",appid);
        requestMap.put("mchid",mchid);
        requestMap.put("description",description);
        requestMap.put("out_trade_no",outTradeNo);
        requestMap.put("attach",attach);
        requestMap.put("notify_url",notifyUrl);
        requestMap.put("amount",amountMap);

        try {
           String codeUrl = run(requestMap);
           return codeUrl;
        } catch (WXPayUtility.ApiException | IOException e) {
            e.printStackTrace();
            return null;
        }
    }


private Logger log = LoggerFactory.getLogger(getClass());
    @Autowired
    private WechatPayConfig config;


    @Override
    public ResponseEntity<Object> paySuccessWeb(HttpServletRequest request, HttpServletResponse response) {
        System.out.println("回调开始了");

        // HTTP 头 `Wechatpay-Signature`。应答的微信支付签名
        String signature = request.getHeader("Wechatpay-Signature");
        // HTTP 头 `Wechatpay-Serial`。微信支付平台证书的序列号，验签必须使用序列号对应的微信支付平台证书。
        String serial = request.getHeader("Wechatpay-Serial");
        // HTTP 头 `Wechatpay-Nonce`。签名中的随机数。
        String nonce = request.getHeader("Wechatpay-Nonce");
        // HTTP 头 `Wechatpay-Timestamp`。签名中的时间戳。
        String timestamp = request.getHeader("Wechatpay-Timestamp");


        StringBuilder sb = null;
        try {
            BufferedReader reader = request.getReader();
            String line;
            sb = new StringBuilder();
            while ((line = reader.readLine()) != null) {
                sb.append(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        String requestBody = sb.toString();


        RequestParam requestParam = new RequestParam.Builder()
                .serialNumber(serial)
                .nonce(nonce)
                .signature(signature)
                .timestamp(timestamp)
                .body(requestBody) // HTTP 请求体 body
                .build();
        // 初始化 `NotificationConfig`，根据回调签名选择使用微信支付公钥或者平台证书选择不同的Config

        NotificationParser parser = new NotificationParser((NotificationConfig) config.rsaAutoCertificateConfig());
        // 以支付通知回调为例，验签、解密并转换成 Transaction
        Transaction transaction = parser.parse(requestParam, Transaction.class);
        // 微信支付侧订单的唯一标识
        String transactionId = transaction.getTransactionId();
        String attach = transaction.getAttach();
        // 交易状态
        // SUCCESS：支付成功
        // REFUND：转入退款
        // NOTPAY：未支付
        // CLOSED：已关闭
        // REVOKED：已撤销（仅付款码支付会返回）
        // USERPAYING：用户支付中（仅付款码支付会返回）
        // PAYERROR：支付失败（仅付款码支付会返回）
        Transaction.TradeStateEnum tradeState = transaction.getTradeState();
        // 如果是支付成功状态
        if (tradeState.equals(Transaction.TradeStateEnum.SUCCESS)) {
            // 业务端更新订单状态和支付成功时间，可以保留微信支付端的响应消息
            // 业务端更新用户金额等
            // 如果存在支付超时关闭订单的操作，此时也可以移除相关操作
            // 此处略去代码
            //处理业务逻辑 TODO
            WebOrder order = new WebOrder();
            order.setPayDate(DateFormatHelper.currentTimes());
            // 获取微信生成的订单号
            order.setTransactionId(transactionId);
            String []attachs = attach.split("@");
            order.setUserId(Integer.parseInt(attachs[0]));
            order.setGoodsName(attachs[1]);
            webOrderMapper.insertSelective(order);

            // 给微信支付端发送通知，防止微信端重复发送响应
            ResponseEntity<Object> notifyRes = ResponseEntity.status(HttpStatus.OK)
                    .build();
            return notifyRes;
        }

        // 如果是支付成功以外的情况，业务端根据自己的情况做处理
        System.out.println(tradeState);
        // 接收消息并处理成功，返回 200 OK 状态码
        return ResponseEntity.status(HttpStatus.OK).build();


    }





    public String  run(Map map) throws IOException {
        String shopPartner = "1729397933";
        String serialNum = "1B23589AA5D706CE5B31BA9FD0392892C391EA18";

        String uri = PATH;
        HttpUrl  httpurl =HttpUrl.parse(HOST + uri);
        String reqBody = WXPayUtility.toJson(map);

        Request.Builder reqBuilder = new Request.Builder().url(HOST + uri);
        reqBuilder.addHeader("Accept", "application/json");
        reqBuilder.addHeader("Authorization", Util.getToken("POST", httpurl, JSONObject.toJSONString(map),
                shopPartner, serialNum));
        reqBuilder.addHeader("Content-Type", "application/json");
        RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), reqBody);
        reqBuilder.method(METHOD, requestBody);
        Request httpRequest = reqBuilder.build();

        // 发送HTTP请求
        OkHttpClient client = new OkHttpClient.Builder().build();
        map = new HashMap();
        try (Response httpResponse = client.newCall(httpRequest).execute()) {
            String respBody = WXPayUtility.extractBody(httpResponse);
            if (httpResponse.code() >= 200 && httpResponse.code() < 300) {
                JSON json = JSONObject.parseObject(respBody);
                String url = ((JSONObject) json).getString("code_url");

                System.out.println(respBody);
               return url;
            } else {
                return null;
            }
        }
    }

    public   void updateUser(Integer userId,String orderNum){
        SUser user = userMapper.selectByPrimaryKey(userId);

        Order order=JSON.parseObject((String)redisTemplate.opsForHash().get("m_"+userId.toString(),"m_"+orderNum), Order.class);
        if(order.getDeductSource()!=0||order.getUsedBalance()!=0){
            user.setUserScore(user.getUserScore()-order.getDeductSource());
            user.setUserBalance(user.getUserBalance()-order.getUsedBalance()+order.getDeductSource());
            user.setUsedPoints(user.getUsedPoints()+order.getDeductSource());
            //获取等级
            if(order.getDeductSource()!=0){
                Example example = new Example(VipLevelNum.class);
                Example.Criteria criteria = example.createCriteria();
                criteria.andGreaterThanOrEqualTo("nextScore",user.getUsedPoints());
                example.orderBy("nextScore").asc();
                List<VipLevelNum> levelNum = levelNumMapper.selectByExample(example);
                if(levelNum.size()>0){
                    user.setVipLevel(levelNum.get(0).getVipLevelNumber());
                }
            }
            userMapper.updateByPrimaryKey(user);
            UserScore score = new UserScore();
            score.setScoreNum(order.getDeductSource());
            score.setScoreType(0);
            score.setUserId(userId);
            score.setOrderNumber(orderNum);
            score.setCreateTime(DateFormatHelper.currentTimes());
            score.setUsedMoney(order.getUsedBalance());
            score.setAcceptMoney(order.getDeductSource());
            score.setDiamondNum(0);
            userScoreMapper.insertSelective(score);
        }
        redisTemplate.opsForHash().delete("m_"+userId.toString(),"m_"+orderNum);
        Object aa = redisTemplate.opsForHash().get("m_"+userId.toString(),"m_"+orderNum);
        System.out.println(aa);
    }

    private void updateUserRecharge(String str){
        //userId + "@"+scoreNum+"@"+diamondNum+@+"commissionNum"+"@"+rechargeMoney
        String  []st = str.split("@");
       SUser user =  userMapper.selectByPrimaryKey(Integer.parseInt(st[0]));
       user.setUserScore(user.getUserScore()+Integer.parseInt(st[1]));
       user.setDiamondNum(user.getDiamondNum()+Integer.parseInt(st[2]));
       if(user.getUserType() == 0){
           user.setUserType(1);
           user.setVipLevel(1);
       }
       userMapper.updateByPrimaryKey(user);
        UserScore score = new UserScore();
        score.setScoreNum(Integer.parseInt(st[1]));
        score.setScoreType(1);
        score.setUserId(Integer.parseInt(st[0]));
        score.setOrderNumber("0");
        score.setCreateTime(DateFormatHelper.currentTimes());
        score.setDiamondNum(Integer.parseInt(st[2]));
        userScoreMapper.insertSelective(score);
        //不是推广员
        if(user.getUserType()!=2){
            //更新我的推广元的佣金信息
            if(user.getParentId()!=0){
                UserCommission commission  = new UserCommission();
                commission.setUserId(user.getParentId());
                commission.setRechargeMoney(Double.valueOf(st[4]));
                commission.setRechargeNum(1);
                commission.setGrantMoney(0.0);
                commission.setTotalMoney(Double.valueOf(st[3]));
                commissionsMapper.addOrUpdate(commission);

                UserCommDetail detail = new UserCommDetail();
                detail.setDetailFlag(0);
                detail.setUserId(user.getParentId());
                detail.setDetailNote("用户"+user.getUserId()+"充值会员");
                detail.setTotalMoney(Double.valueOf(st[3]));
                detail.setDateTime(DateFormatHelper.currentTimes());
                detail.setRechargeNum(Double.valueOf(st[4]));
                detail.setRechargeId(Integer.parseInt(st[0]));
                detailsMapper.insertSelective(detail);
            }



            //我的上级不是我的推广员
            if(user.getShareId()!=user.getParentId()){
                //获取我的上级所有的会员身份
                List<SUser> users = userMapper.selectByExample(new Example(SUser.class).createCriteria().andEqualTo("shareId",user.getShareId()));
                if(users.size()>=5){
                    SUser shareUser = new SUser();
                    shareUser.setHasZg(1);
                    shareUser.setUserId(user.getShareId());
                    userMapper.updateByPrimaryKeySelective(shareUser);
                }
            }
        }

        //更新奖池的剩余报销额度
        pondMapper.updatePond(Integer.parseInt(st[1]));

    }



    @Override
    public List<WebOrder> getUserInfo(Integer userId) {
        Example example =new Example(WebOrder.class);
        Example.Criteria criteria =  example.createCriteria();
        criteria.andEqualTo("userId",userId);
        List<WebOrder> webOrders = webOrderMapper.selectByExample(example);
        return webOrders;
    }


    private  void testPaySuccess(String orderNum,Integer userId){
        Example example =new Example(Order.class);
        Example.Criteria criteria =  example.createCriteria();
        criteria.andEqualTo("numberFlag",orderNum);
        Order order = new Order();
        order.setOrderStatus(1);
        orderMapper.updateByExampleSelective(order,example);
        //更新用户账户
         updateUser(userId,orderNum);
    }

}
